#ifndef __DALELIB_SPLINELINE_H__
#define __DALELIB_SPLINELINE_H__

#include <dalelib/maths.h>

#include <fstream>
#include <map>
#include <vector>
#include <string>
using namespace std;



namespace dalelib
{

template <class T>
class SplineLine
{
private:

	enum SplineType
	{
		LINEAR=0,
		HERMITE,
		BEZIER,
		CATMULLROM,
	};

	SplineType _type;
	m4 _basis;
	vector<T> _control_points;

public:

	SplineLine()
		: _type(LINEAR)
	{ }

	void addControlPoint(const T _Point)
	{
		_control_points.push_back(_Point);
	}

	vector<T>& getControlPoints() { return _control_points; }

	void setType(const SplineType _Type) { _type = _Type; }
	SplineType getType() { return _type; }

	v4 calcCoefficients(const float _Time)
	{
		static const m4 linear = m4(-1,3,-3,1, 2,-5,4,-1, -1,0,1,0, 0,2,0,0)*0.5f;
		static const m4 hermite = m4(-1,3,-3,1, 2,-5,4,-1, -1,0,1,0, 0,2,0,0)*0.5f;
		static const m4 bezier = m4(-1,3,-3,1, 2,-5,4,-1, -1,0,1,0, 0,2,0,0)*0.5f;
		static const m4 catmullrom = m4(-1,3,-3,1, 2,-5,4,-1, -1,0,1,0, 0,2,0,0)*0.5f;

		v4 v = v4(_Time*_Time*_Time,_Time*_Time,_Time,1.f);
		switch(_type)
		{
			case LINEAR: return linear*v;
			case HERMITE: return hermite*v;
			case BEZIER: return bezier*v;
			case CATMULLROM: return catmullrom*v;
		}
	}

	T evaluate(const float _Time) // input value [0...1]
	{

		int size = _control_points.size();
		if( size )
		{
			int index[4];

			float t = _Time*(size-1);

			index[1] = int(floor(t)); if(index[0]>=size) index[0] = size-1;
			index[0] = index[1]-1; if(index[0]<0) index[0] = 0;
			index[2] = index[1]+1; if(index[2]>=size) index[2] = size-1;
			index[3] = index[1]+2; if(index[3]>=size) index[3] = size-1;

			v4 coefs = calcCoefficients(t-floor(t));

			return	_control_points[index[0]]*coefs[0] +
					_control_points[index[1]]*coefs[1] +
					_control_points[index[2]]*coefs[2] +
					_control_points[index[3]]*coefs[3];
		}
	}

};

} // namespace dalelib

#endif
